package sg.edu.nus.iss.billing.controller;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import sg.edu.nus.iss.billing.constant.ErrorCodeConstants;
import sg.edu.nus.iss.billing.entity.Account;
import sg.edu.nus.iss.billing.entity.Bill;
import sg.edu.nus.iss.billing.entity.PaymentHistory;
import sg.edu.nus.iss.billing.entity.transaction.CallTransaction;
import sg.edu.nus.iss.billing.entity.transaction.Transaction;
import sg.edu.nus.iss.billing.exception.ControllerException;
import sg.edu.nus.iss.billing.exception.TemplateEngineException;
import sg.edu.nus.iss.billing.localization.MessageKeyManager;
import sg.edu.nus.iss.billing.parse.PaymentFileParser;
import sg.edu.nus.iss.billing.parse.TransactionFileParser;
import sg.edu.nus.iss.billing.template.BillingTemplate;
import sg.edu.nus.iss.billing.template.FileOutputParseActionProcessor;
import sg.edu.nus.iss.billing.template.OneTelcoParseActionProcessor;
import sg.edu.nus.iss.billing.template.interfaces.ParseActionProcessor;

/**
 * @author Daniel
 *
 */
public class BillGenerator {
	
	private static TransactionFileParser transactionFileParser = null;
	private static PaymentFileParser paymentFileParser =  null;
	private void initTransactionalData(Account acc) throws ControllerException {
	    if (transactionFileParser == null) {
			transactionFileParser = new TransactionFileParser();
	        try {
	            transactionFileParser.parse("data/transaction-data.txt");
	        } catch (IOException e) {
	            throw new ControllerException(ErrorCodeConstants.ERROR_TEMPLATE_ENGINE_UNKNOWN, MessageKeyManager.getMessage("error.template.unknown", e.getMessage()));
	        }
		}
        List<CallTransaction> callTransactionList = transactionFileParser.getCallListByAccount(acc.getAccountNumber());
        List<Transaction> transactionList = new ArrayList<Transaction>();
        if (callTransactionList != null) {
            for (int i=0; i < callTransactionList.size(); i++) {
                
                transactionList.add(callTransactionList.get(i));
            }
        }
        acc.setTransactions(transactionList);
        List<PaymentHistory> paymentHistoryList = null;
        if (paymentFileParser == null) {
	        try {
		        paymentFileParser = new PaymentFileParser();
		        paymentFileParser.parse("data/payment-data.txt");
	        } catch (IOException e) {
	            throw new ControllerException(ErrorCodeConstants.ERROR_TEMPLATE_ENGINE_UNKNOWN, MessageKeyManager.getMessage("error.template.unknown", e.getMessage()));
	        }
        }
        paymentHistoryList = paymentFileParser.getPaymentHistoryByAccount(acc.getAccountNumber());
        
        if (paymentHistoryList != null) {
            acc.setPaymentHistories(paymentHistoryList);
        } else {
            acc.setPaymentHistories(new ArrayList<PaymentHistory>());
        }
	}
	
	private String readFile(File sourceFileName) throws IOException {
		
		StringBuffer sbuf = new StringBuffer();
		FileReader fstream = null;
		BufferedReader br = null;
		fstream = new FileReader(sourceFileName);
		br = new BufferedReader(fstream);
		String s = null;
		while((s = br.readLine()) != null) {
			sbuf.append(s);
		} 
		br.close();
		fstream.close();
		return sbuf.toString();
	}
	
	private void saveBackAccountBalance(Account acc, Bill bill) throws ControllerException {
		if (bill.getTotalBalance() != null) {
			acc.setBalance(bill.getTotalBalance());
		}
		try {
			AccountController accController = new AccountController();
			accController.editAccount(acc);
		} catch (ControllerException e) {
			throw e;
		}
	}
	
	public String generateBill(Calendar cal, Account acc, File file) throws ControllerException {
		String monthString = String.valueOf(cal.get(Calendar.MONTH));
		String yearString = String.valueOf(cal.get(Calendar.YEAR));
		ParseActionProcessor processor = null;
		try {
			if (file.exists()) {
				return readFile(file);
			}
		} catch (IOException e) {
			throw new ControllerException(ErrorCodeConstants.UNKNOWN_ERROR, e.getMessage());
		}
		
		
		if (acc != null) {
		    initTransactionalData(acc);
			BillCalculator billCalculator = new BillCalculator(acc, monthString, yearString);
			try {
				Bill bill = billCalculator.calculate();
				
				BillingTemplate template = new BillingTemplate("templateEngine/template/billing.html");
				processor = new OneTelcoParseActionProcessor(template, bill);
				FileOutputParseActionProcessor decoratorProcessor = new FileOutputParseActionProcessor(processor, file);
				decoratorProcessor.process();
				processor.getParsedString(); //htmlString
				//System.out.println(processor.getParsedString());
				saveBackAccountBalance(acc, bill);
			} catch (TemplateEngineException e) {
				throw new ControllerException(ErrorCodeConstants.ERROR_TEMPLATE_ENGINE_UNKNOWN, MessageKeyManager.getMessage("error.template.unknown", e.getMessage()));
			} catch (ControllerException e) {
				throw e;
			} catch (Exception e) {
				throw new ControllerException(ErrorCodeConstants.ERROR_TEMPLATE_ENGINE_UNKNOWN, MessageKeyManager.getMessage("error.template.unknown", e.getMessage()));
			}
		} else {
			throw new ControllerException(ErrorCodeConstants.ERROR_ACCOUNT_NOT_FOUND, MessageKeyManager.getMessage("error.accountNotFound"));
		}
		if (processor != null) {
			return processor.getParsedString();
		} else {
			return "";
		}
	}

}
